﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using Microsoft.Office.Interop.Word;
using System.Windows.Documents;
using System.Windows.Markup;

namespace WordFlowDocumentCreator
{
    /// <summary>
    /// Class to create WPF FlowDocuments
    /// </summary>
    public class FlowDocumentCreator
    {
        #region Member data
        FlowDocumentOptions m_options;
        #endregion

        #region Constructors
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="options"></param>
        public FlowDocumentCreator(FlowDocumentOptions options)
        {
            m_options = options;
        }
        #endregion

        #region Methods
        /// <summary>
        /// Show a flow document
        /// </summary>
        /// <param name="wordOpenXml"></param>
        public void ShowFlowDocument(string wordOpenXml)
        {
            Cursor.Current = Cursors.WaitCursor;

            System.Xml.Xsl.XslCompiledTransform transform = CreateTransform(m_options.IsWPF);

            System.Xml.XmlDocument doc = new XmlDocument();

            doc.LoadXml(wordOpenXml);

            StringWriter textWriter = new StringWriter(System.Globalization.CultureInfo.InvariantCulture);

            XmlTextWriter writer = new XmlTextWriter(textWriter);
            writer.Indentation = 4;
            writer.Formatting = Formatting.Indented;

            System.Xml.Xsl.XsltArgumentList arguments = new System.Xml.Xsl.XsltArgumentList();

            PreviewDocument preview = new PreviewDocument();

            //string directory = System.IO.Path.GetDirectoryName(dialog.FileName);

            arguments.AddExtensionObject("http://blogs.msdn.com/synergist/imaging", new Imaging(preview.Resources));

            SetArguments(arguments);

            transform.Transform(doc, arguments, writer);

            writer.Close();

            string xaml = textWriter.GetStringBuilder().ToString();

            if (m_options.IsWPF)
            {
                PreviewWPF(preview, xaml);
            }
            else
            {
                PreviewSilverlight(xaml);
            }
        }

        static void PreviewSilverlight(string xaml)
        {
            var tempDirectory = Path.GetTempPath() + @"\WordFlowDocumentCreator Silverlight App";

            if (!Directory.Exists(tempDirectory))
            {
                Directory.CreateDirectory(tempDirectory);
            }

            using (System.IO.StreamWriter writer = new StreamWriter(tempDirectory + @"\Normal.css"))
            {
                writer.WriteLine(Properties.Resources.Normal);
                writer.Flush();
            }

            using (var writer = new StreamWriter(tempDirectory + @"\SilverlightHandling.js"))
            {
                writer.WriteLine(Properties.Resources.SilverlightHandling);
                writer.Flush();
            }

            System.Xml.XmlDocument doc = new XmlDocument();
            
            doc.Load(new StringReader(Properties.Resources.preview));

            var xamlText = doc.GetElementsByTagName("textarea")[0];

            xamlText.InnerText = xaml;

            var previewHtml = tempDirectory + @"\preview.html";

            doc.Save(previewHtml);

            if (!Directory.Exists(tempDirectory + @"\ClientBin"))
            {
                Directory.CreateDirectory(tempDirectory + @"\ClientBin");
            }

            using (var file = File.Create(tempDirectory + @"\ClientBin\PreviewSilverlight.xap"))
            {
                file.Write(Properties.Resources.PreviewSilverlight, 0, Properties.Resources.PreviewSilverlight.Length);

                file.Flush();
            }

            System.Diagnostics.Process.Start(previewHtml);
        }

        private static void PreviewWPF(PreviewDocument preview, string xaml)
        {
            XmlTextReader reader = new XmlTextReader(xaml, XmlNodeType.Document, null);

            FlowDocument flowDocument = XamlReader.Load(reader) as FlowDocument;

            preview.Content = flowDocument;

            System.Collections.IDictionaryEnumerator enumerator = preview.Resources.GetEnumerator();
            enumerator.MoveNext();

            Cursor.Current = Cursors.Default;

            preview.ShowDialog();
        }

        /// <summary>
        /// Show XAML using the preview document
        /// </summary>
        /// <param name="xaml">valid XAML</param>
        public static void ShowXaml(string xaml)
        {
            PreviewDocument preview = new PreviewDocument();

            XmlTextReader reader = new XmlTextReader(xaml, XmlNodeType.Document, null);

            FlowDocument flowDocument = XamlReader.Load(reader) as FlowDocument;

            preview.Content = flowDocument;

            preview.ShowDialog();
        }

        /// <summary>
        /// Create a new flow document
        /// </summary>
        /// <param name="document"></param>
        public void Create(Document document)
        {
            using (System.Windows.Forms.SaveFileDialog dialog = new System.Windows.Forms.SaveFileDialog())
            {
                dialog.FileName = System.IO.Path.ChangeExtension(document.Name, Properties.Resources.FileExtension);
                dialog.Filter = Properties.Resources.Filters;
                dialog.DefaultExt = Properties.Resources.FileExtension;
                dialog.Title = Properties.Resources.SaveAsTitle;

                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    Cursor.Current = Cursors.WaitCursor;

                    using (CreatingWpf progressForm = new CreatingWpf(4))
                    {
                        progressForm.Load += delegate(object loadSender, EventArgs loadEventArgs)
                        {
                            progressForm.StepProgress("Loading Transform...");

                            System.Xml.Xsl.XslCompiledTransform transform = CreateTransform(m_options.IsWPF);

                            System.Xml.XmlDocument doc = new XmlDocument();

                            progressForm.StepProgress("Getting Word Open XML...");

                            doc.LoadXml(document.WordOpenXML);

                            System.Diagnostics.Trace.WriteLine(doc.InnerXml);

                            XmlTextWriter writer = new XmlTextWriter(dialog.FileName, Encoding.UTF8);
                            writer.Indentation = 4;
                            writer.Formatting = Formatting.Indented;

                            progressForm.StepProgress("Transforming...");

                            System.Xml.Xsl.XsltArgumentList arguments = new System.Xml.Xsl.XsltArgumentList();

                            string directory = System.IO.Path.GetDirectoryName(dialog.FileName);

                            arguments.AddExtensionObject("http://blogs.msdn.com/synergist/imaging", new Imaging(directory));
                            SetArguments(arguments);

                            transform.Transform(doc, arguments, writer);

                            writer.Close();

                            progressForm.StepProgress("Done.");

                            progressForm.Close();
                        };

                        progressForm.ShowDialog();
                    }

                    Cursor.Current = Cursors.Default;

                    System.Diagnostics.Process.Start(dialog.FileName);
                }
            }
        }
        #endregion

        #region Implementation
        private static System.Xml.Xsl.XslCompiledTransform CreateTransform(bool IsWPF)
        {
            System.Xml.Xsl.XslCompiledTransform transform = new System.Xml.Xsl.XslCompiledTransform(true);

            string streamName;

            if (IsWPF)
            {
                streamName = "WordFlowDocumentCreator.WordMLtoWPF.xslt";
            }
            else
            {
                streamName = "WordFlowDocumentCreator.WordMLtoSilverlight2.xslt";
            }

            using (Stream s = typeof(FlowDocumentCreator).Assembly.GetManifestResourceStream(streamName))
            {
                transform.Load(new XmlTextReader(s));
            }

            return transform;
        }

        void SetArguments(System.Xml.Xsl.XsltArgumentList arguments)
        {
            arguments.AddParam("IsOptimalParagraphEnabled", "", m_options.IsOptimalParagraphEnabled);
            arguments.AddParam("IsHyphenationEnabled", "", m_options.IsHyphenationEnabled);
            arguments.AddParam("IsColumnWidthFlexible", "", m_options.IsColumnWidthFlexible);
            string pagePadding = "Auto";
            if (!m_options.AutoPagePadding)
            {
                pagePadding = m_options.PagePadding.ToString(System.Globalization.CultureInfo.InvariantCulture) + m_options.PagePaddingUnits;
            }

            arguments.AddParam("PagePadding", "", pagePadding);

            string columnWidth = "Auto";

            if (!m_options.AutoColumnWidth)
            {
                columnWidth = m_options.ColumnWidth.ToString(System.Globalization.CultureInfo.InvariantCulture) + m_options.ColumnWidthUnits;
            }

            arguments.AddParam("ColumnWidth", "", columnWidth);
        }
        #endregion
    }
}
